#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Excel导入对话框模块 - 用于从Excel导入监控项和触发器配置
"""

import logging
import os
import json
from typing import Dict, List, Any, Optional, Tuple
from PyQt5.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, 
    QTabWidget, QWidget, QTableWidget, QTableWidgetItem,
    QHeaderView, QPushButton, QMessageBox, QProgressBar,
    QComboBox, QFormLayout
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, pyqtSlot

import pandas as pd
from src.zabbix_api import ZabbixAPI

logger = logging.getLogger(__name__)


class ImportWorker(QThread):
    """导入工作线程"""
    
    # 信号定义
    progress = pyqtSignal(int)  # 进度信号
    status = pyqtSignal(str)    # 状态信息信号
    error = pyqtSignal(str)     # 错误信号
    finished = pyqtSignal(bool, dict)  # 完成信号，带成功状态和结果
    
    def __init__(self, api: ZabbixAPI, file_path: str, item_sheet: str, trigger_sheet: str, parent=None):
        """
        初始化导入工作线程
        
        Args:
            api (ZabbixAPI): Zabbix API客户端
            file_path (str): Excel文件路径
            item_sheet (str): 监控项表格名称
            trigger_sheet (str): 触发器表格名称
            parent: 父对象
        """
        super().__init__(parent)
        self.api = api
        self.file_path = file_path
        self.item_sheet = item_sheet
        self.trigger_sheet = trigger_sheet
        self.is_running = False
    
    def run(self):
        """线程执行主方法"""
        self.is_running = True
        
        try:
            self.status.emit("开始读取Excel文件...")
            
            # 加载Excel文件
            with pd.ExcelFile(self.file_path) as xls:
                # 检查表格是否存在
                if self.item_sheet and self.item_sheet in xls.sheet_names:
                    items_df = pd.read_excel(xls, self.item_sheet)
                else:
                    items_df = None
                
                if self.trigger_sheet and self.trigger_sheet in xls.sheet_names:
                    triggers_df = pd.read_excel(xls, self.trigger_sheet)
                else:
                    triggers_df = None
            
            result = {"items": {"success": 0, "failed": 0}, "triggers": {"success": 0, "failed": 0}}
            
            # 处理监控项
            if items_df is not None and not items_df.empty:
                self.status.emit("处理监控项...")
                self.progress.emit(10)
                
                # 预处理数据
                items_df = items_df.fillna("")
                
                # 转换为Zabbix API可接受的格式
                items = []
                for _, row in items_df.iterrows():
                    if not self.is_running:
                        break
                    
                    try:
                        item = {
                            "hostid": str(row.get("hostid", "")),
                            "name": str(row.get("name", "")),
                            "key_": str(row.get("key", "")),
                            "type": int(row.get("type", 0)),
                            "value_type": int(row.get("value_type", 0)),
                            "delay": str(row.get("delay", "60s")),
                            "history": str(row.get("history", "90d")),
                            "trends": str(row.get("trends", "365d")),
                            "description": str(row.get("description", "")),
                            "units": str(row.get("units", ""))
                        }
                        
                        # 检查必填项
                        if not item["hostid"] or not item["name"] or not item["key_"]:
                            result["items"]["failed"] += 1
                            logger.warning(f"监控项缺少必填字段，行号: {_}")
                            continue
                        
                        items.append(item)
                    except Exception as e:
                        logger.error(f"处理监控项行失败: {e}")
                        result["items"]["failed"] += 1
                
                # 批量创建监控项
                if items and self.is_running:
                    try:
                        self.status.emit(f"创建 {len(items)} 个监控项...")
                        self.progress.emit(40)
                        
                        api_result = self.api.create_items(items)
                        result["items"]["success"] = len(api_result.get("itemids", []))
                    except Exception as e:
                        logger.error(f"批量创建监控项失败: {e}")
                        self.error.emit(f"创建监控项时发生错误: {e}")
                        result["items"]["failed"] += len(items)
            
            self.progress.emit(50)
            
            # 处理触发器
            if triggers_df is not None and not triggers_df.empty:
                self.status.emit("处理触发器...")
                self.progress.emit(60)
                
                # 预处理数据
                triggers_df = triggers_df.fillna("")
                
                # 转换为Zabbix API可接受的格式
                triggers = []
                for _, row in triggers_df.iterrows():
                    if not self.is_running:
                        break
                    
                    try:
                        trigger = {
                            "description": str(row.get("description", "")),
                            "expression": str(row.get("expression", "")),
                            "priority": int(row.get("priority", 3)),
                            "comments": str(row.get("comments", "")),
                            "status": int(row.get("status", 0)),
                            "type": int(row.get("type", 0))
                        }
                        
                        # 检查必填项
                        if not trigger["description"] or not trigger["expression"]:
                            result["triggers"]["failed"] += 1
                            continue
                        
                        # 解析JSON字段
                        if row.get("tags") and str(row.get("tags")) != "":
                            try:
                                tags = json.loads(str(row.get("tags")))
                                if tags:
                                    trigger["tags"] = tags
                            except:
                                pass
                        
                        if row.get("dependencies") and str(row.get("dependencies")) != "":
                            try:
                                dependencies = json.loads(str(row.get("dependencies")))
                                if dependencies:
                                    trigger["dependencies"] = dependencies
                            except:
                                pass
                        
                        triggers.append(trigger)
                    except Exception as e:
                        logger.error(f"处理触发器行失败: {e}")
                        result["triggers"]["failed"] += 1
                
                # 批量创建触发器
                if triggers and self.is_running:
                    try:
                        self.status.emit(f"创建 {len(triggers)} 个触发器...")
                        self.progress.emit(90)
                        
                        api_result = self.api.create_triggers(triggers)
                        result["triggers"]["success"] = len(api_result.get("triggerids", []))
                    except Exception as e:
                        logger.error(f"批量创建触发器失败: {e}")
                        self.error.emit(f"创建触发器时发生错误: {e}")
                        result["triggers"]["failed"] += len(triggers)
            
            self.progress.emit(100)
            self.status.emit("导入完成!")
            self.finished.emit(True, result)
            
        except Exception as e:
            logger.error(f"导入过程发生错误: {e}")
            self.error.emit(f"导入过程中发生错误: {e}")
            self.finished.emit(False, {})
        
        self.is_running = False
    
    def stop(self):
        """停止线程"""
        self.is_running = False


class ExcelImportDialog(QDialog):
    """Excel导入对话框"""
    
    def __init__(self, api: ZabbixAPI, file_path: str, parent=None):
        """
        初始化Excel导入对话框
        
        Args:
            api (ZabbixAPI): Zabbix API客户端
            file_path (str): Excel文件路径
            parent: 父窗口
        """
        super().__init__(parent)
        self.api = api
        self.file_path = file_path
        self.worker = None
        self.sheet_names = []
        self.setup_ui()
        self.load_excel_info()
    
    def setup_ui(self):
        """设置UI界面"""
        self.setWindowTitle("导入Excel配置")
        self.resize(700, 500)
        self.setModal(True)
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 显示文件信息
        file_info_layout = QFormLayout()
        self.file_label = QLabel(self.file_path)
        file_info_layout.addRow("文件路径:", self.file_label)
        
        # 表格选择
        sheet_selection = QWidget()
        sheet_layout = QFormLayout(sheet_selection)
        
        self.item_sheet_combo = QComboBox()
        sheet_layout.addRow("监控项表格:", self.item_sheet_combo)
        
        self.trigger_sheet_combo = QComboBox()
        sheet_layout.addRow("触发器表格:", self.trigger_sheet_combo)
        
        file_info_layout.addRow("", sheet_selection)
        main_layout.addLayout(file_info_layout)
        
        # 创建标签页面
        self.tab_widget = QTabWidget()
        main_layout.addWidget(self.tab_widget)
        
        # 创建预览表格
        self.preview_items_table = QTableWidget()
        self.preview_items_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.tab_widget.addTab(self.preview_items_table, "监控项预览")
        
        self.preview_triggers_table = QTableWidget()
        self.preview_triggers_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.tab_widget.addTab(self.preview_triggers_table, "触发器预览")
        
        # 创建状态栏
        status_layout = QVBoxLayout()
        
        self.status_label = QLabel("准备就绪")
        status_layout.addWidget(self.status_label)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        status_layout.addWidget(self.progress_bar)
        
        main_layout.addLayout(status_layout)
        
        # 创建按钮布局
        button_layout = QHBoxLayout()
        
        self.reload_btn = QPushButton("重新加载")
        self.reload_btn.clicked.connect(self.load_excel_info)
        
        self.import_btn = QPushButton("开始导入")
        self.import_btn.clicked.connect(self.start_import)
        
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.reject)
        
        button_layout.addWidget(self.reload_btn)
        button_layout.addWidget(self.import_btn)
        button_layout.addWidget(self.cancel_btn)
        
        main_layout.addLayout(button_layout)
        
        # 连接信号
        self.item_sheet_combo.currentTextChanged.connect(lambda: self.load_preview(self.item_sheet_combo.currentText(), "items"))
        self.trigger_sheet_combo.currentTextChanged.connect(lambda: self.load_preview(self.trigger_sheet_combo.currentText(), "triggers"))
    
    def load_excel_info(self):
        """加载Excel文件信息"""
        try:
            # 保存当前选择
            current_item_sheet = self.item_sheet_combo.currentText()
            current_trigger_sheet = self.trigger_sheet_combo.currentText()
            
            # 读取Excel文件的表格名称
            xls = pd.ExcelFile(self.file_path)
            self.sheet_names = xls.sheet_names
            
            # 清空并重新填充下拉框
            self.item_sheet_combo.clear()
            self.trigger_sheet_combo.clear()
            
            self.item_sheet_combo.addItem("")  # 添加空选项
            self.trigger_sheet_combo.addItem("")  # 添加空选项
            
            for sheet in self.sheet_names:
                self.item_sheet_combo.addItem(sheet)
                self.trigger_sheet_combo.addItem(sheet)
            
            # 恢复选择
            if current_item_sheet and current_item_sheet in self.sheet_names:
                self.item_sheet_combo.setCurrentText(current_item_sheet)
            elif self.sheet_names and "items" in [s.lower() for s in self.sheet_names]:
                # 尝试找到名为"items"的表格
                for sheet in self.sheet_names:
                    if sheet.lower() == "items":
                        self.item_sheet_combo.setCurrentText(sheet)
                        break
            
            if current_trigger_sheet and current_trigger_sheet in self.sheet_names:
                self.trigger_sheet_combo.setCurrentText(current_trigger_sheet)
            elif self.sheet_names and "triggers" in [s.lower() for s in self.sheet_names]:
                # 尝试找到名为"triggers"的表格
                for sheet in self.sheet_names:
                    if sheet.lower() == "triggers":
                        self.trigger_sheet_combo.setCurrentText(sheet)
                        break
            
            # 加载预览
            if self.item_sheet_combo.currentText():
                self.load_preview(self.item_sheet_combo.currentText(), "items")
            
            if self.trigger_sheet_combo.currentText():
                self.load_preview(self.trigger_sheet_combo.currentText(), "triggers")
            
            self.status_label.setText("Excel文件已加载")
            
        except Exception as e:
            logger.error(f"加载Excel文件失败: {e}")
            QMessageBox.critical(self, "加载失败", f"无法加载Excel文件: {e}")
    
    def load_preview(self, sheet_name: str, preview_type: str):
        """
        加载预览表格
        
        Args:
            sheet_name (str): 表格名称
            preview_type (str): 预览类型，"items"或"triggers"
        """
        if not sheet_name:
            return
        
        try:
            # 读取Excel表格
            df = pd.read_excel(self.file_path, sheet_name)
            
            # 根据类型选择表格
            table = self.preview_items_table if preview_type == "items" else self.preview_triggers_table
            
            # 清空表格
            table.clear()
            table.setRowCount(0)
            table.setColumnCount(0)
            
            # 设置表头
            columns = df.columns.tolist()
            table.setColumnCount(len(columns))
            table.setHorizontalHeaderLabels(columns)
            
            # 填充数据（最多显示100行）
            max_rows = min(100, len(df))
            table.setRowCount(max_rows)
            
            for i in range(max_rows):
                for j, col in enumerate(columns):
                    val = str(df.iloc[i, j])
                    table.setItem(i, j, QTableWidgetItem(val))
            
            # 调整列宽
            table.resizeColumnsToContents()
            
            # 如果是监控项预览，切换到对应标签页
            if preview_type == "items":
                self.tab_widget.setCurrentIndex(0)
            else:
                self.tab_widget.setCurrentIndex(1)
            
        except Exception as e:
            logger.error(f"加载预览失败: {e}")
            QMessageBox.warning(self, "预览失败", f"无法加载表格预览: {e}")
    
    def start_import(self):
        """开始导入"""
        # 检查是否选择了表格
        if not self.item_sheet_combo.currentText() and not self.trigger_sheet_combo.currentText():
            QMessageBox.warning(self, "验证失败", "请至少选择一个表格导入")
            return
        
        # 创建并启动工作线程
        self.worker = ImportWorker(
            self.api,
            self.file_path,
            self.item_sheet_combo.currentText(),
            self.trigger_sheet_combo.currentText()
        )
        
        # 连接信号
        self.worker.progress.connect(self.progress_bar.setValue)
        self.worker.status.connect(self.status_label.setText)
        self.worker.error.connect(self.show_error)
        self.worker.finished.connect(self.import_finished)
        
        # 禁用按钮
        self.import_btn.setEnabled(False)
        self.reload_btn.setEnabled(False)
        
        # 启动线程
        self.worker.start()
    
    @pyqtSlot(str)
    def show_error(self, message: str):
        """显示错误信息"""
        QMessageBox.critical(self, "导入错误", message)
    
    @pyqtSlot(bool, dict)
    def import_finished(self, success: bool, result: Dict[str, Any]):
        """导入完成处理函数"""
        # 重新启用按钮
        self.import_btn.setEnabled(True)
        self.reload_btn.setEnabled(True)
        
        if success:
            items_success = result.get("items", {}).get("success", 0)
            items_failed = result.get("items", {}).get("failed", 0)
            triggers_success = result.get("triggers", {}).get("success", 0)
            triggers_failed = result.get("triggers", {}).get("failed", 0)
            
            message = f"导入完成\n\n监控项: {items_success}个成功，{items_failed}个失败\n触发器: {triggers_success}个成功，{triggers_failed}个失败"
            QMessageBox.information(self, "导入完成", message)
            
            if items_success > 0 or triggers_success > 0:
                self.accept()
        else:
            self.status_label.setText("导入失败")
    
    def reject(self):
        """取消按钮处理函数"""
        if self.worker and self.worker.isRunning():
            reply = QMessageBox.question(
                self, "确认取消", 
                "导入过程正在进行中，确定要取消吗？",
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                self.worker.stop()
                super().reject()
        else:
            super().reject() 